/**
 * 
 */
package edu.gatech.oad.mule.view;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.LayoutManager;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JPanel;

import edu.gatech.oad.mule.view.interfaces.RenderableGameDriver;
import edu.gatech.oad.mule.view.interfaces.RenderableMap;
import edu.gatech.oad.mule.view.interfaces.RenderablePlayer;
import edu.gatech.oad.mule.view.interfaces.RenderableTile;
import edu.gatech.oad.mule.view.interfaces.RenderableWorldMap;
import edu.gatech.oad.mule.view.interfaces.RenderableMap.MapType;
import edu.gatech.oad.mule.view.interfaces.RenderableTile.ProductionType;
import edu.gatech.oad.mule.view.interfaces.RenderableTile.TileType;

/**
 * @author Dale Avery
 * 
 */
final class LandGrantPanel extends JPanel {

	// World map graphics.
	private static Image TILE_PLAINS;
	private static Image TILE_MOUNTAIN1;
	private static Image TILE_MOUNTAIN2;
	private static Image TILE_MOUNTAIN3;
	private static Image TILE_RIVER;
	private static Image TILE_TOWN;
	private static Image TILE_PROD_CRYSTITE;
	private static Image TILE_PROD_ENERGY;
	private static Image TILE_PROD_ORE;
	private static Image TILE_PROD_FOOD;

	private static int MAP_TILE_WIDTH = 9;
	private static int MAP_TILE_HEIGHT = 5;
	private static float RECTANGLE_THICKNESS = 4f;
	
	private RenderableGameDriver driver;
	private JLabel title;

	/**
	 * 
	 */
	public LandGrantPanel(Dimension dimension, RenderableGameDriver driver) {
		// Save the game driver so that we can render frames.
		this.driver = driver;
		try {
			// Attempt to load the graphic for the intro screen.
			ClassLoader classLoader = Thread.currentThread()
					.getContextClassLoader();

			// Load world map graphics.
			InputStream input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_PLAINS.png");
			TILE_PLAINS = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_MOUNTAIN1.png");
			TILE_MOUNTAIN1 = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_MOUNTAIN2.png");
			TILE_MOUNTAIN2 = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_MOUNTAIN3.png");
			TILE_MOUNTAIN3 = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_RIVER.png");
			TILE_RIVER = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_TOWN.png");
			TILE_TOWN = ImageIO.read(input);

			// Load production graphics.
			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_PROD_CRYSTITE.png");
			TILE_PROD_CRYSTITE = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_PROD_ENERGY.png");
			TILE_PROD_ENERGY = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_PROD_ORE.png");
			TILE_PROD_ORE = ImageIO.read(input);

			input = classLoader
					.getResourceAsStream("edu/gatech/oad/mule/graphics/screens/TILE_PROD_FOOD.png");
			TILE_PROD_FOOD = ImageIO.read(input);

			setPreferredSize(dimension);
			this.setLayout(new BorderLayout());
			title = new JLabel();
			this.add(title, BorderLayout.NORTH);
			
		} catch (IOException e) {
			System.out.println("ERROR: failed to create LandGrantPanel");
			e.printStackTrace();
		}
	}

	@Override
	public void paintComponent(Graphics g) {
		// Let UI Delegate paint first, which
		// includes background filling since
		// this component is opaque.

		super.paintComponent(g);
		RenderableMap map = driver.getCurrentMap();

		// Paint the map to the screen.
		if (map.getMapType() == MapType.WORLD) {
			renderWorldMap(g, (RenderableWorldMap) map);
			title.setText("" + driver.getCurrentPlayer());
		} else {
			// TODO throw an error or display an error screen.
		}
	}

	/**
	 * Renders a single frame of a world map.
	 * 
	 * @param g
	 *            The graphics object to draw the frame to.
	 * @param map
	 *            The map from which frame data is obtained.
	 */
	private void renderWorldMap(Graphics g, RenderableWorldMap map) {
		// Calculate scaled values to draw maps at any resolution.
		int tileWidth = this.getWidth() / MAP_TILE_WIDTH;
		int tileHeight = this.getHeight() / MAP_TILE_HEIGHT;
		Dimension dim = map.getSize();
		double positionScaleWidth = (double) this.getWidth() / dim.width;
		double positionScaleHeight = (double) this.getHeight() / dim.height;

		// Render all tiles to the screen.
		RenderableTile[] tiles = map.getTiles();

		for (RenderableTile tile : tiles) {
			int x = (int) (tile.getX() * positionScaleWidth);
			int y = (int) (tile.getY() * positionScaleHeight);

			// Draw the base layer of the tile.
			g.drawImage(getImage(tile), x, y, tileWidth, tileHeight, null);

			// Draw the production on the tile
			if (tile.getProductionType() != ProductionType.NO_MULE)
				g.drawImage(getProductionImage(tile), x, y, tileWidth,
						tileHeight, null);

			// Draw the owners color on the tile.
			if (tile.getOwnerColor() != null) {
				Graphics2D g2 = (Graphics2D) g;
				g2.setColor(tile.getOwnerColor());
				g2.setStroke(new BasicStroke(RECTANGLE_THICKNESS));
				g2.drawRect((int) (x + RECTANGLE_THICKNESS),
						(int) (y + RECTANGLE_THICKNESS),
						(int) (tileWidth - 2 * RECTANGLE_THICKNESS),
						(int) (tileHeight - 2 * RECTANGLE_THICKNESS));
			}
			
			// Draw the selection box on the tile.
			if (tile.equals(driver.getCurrentTile())) {
				Graphics2D g2 = (Graphics2D) g;
				g2.setColor(Color.WHITE);
				g2.setStroke(new BasicStroke(RECTANGLE_THICKNESS));
				g2.drawRect((int) (x + RECTANGLE_THICKNESS),
						(int) (y + RECTANGLE_THICKNESS),
						(int) (tileWidth - 2 * RECTANGLE_THICKNESS),
						(int) (tileHeight - 2 * RECTANGLE_THICKNESS));
			}
		}
	}

	/**
	 * @param tile
	 *            A tile for which an image is needed.
	 * @return The image that corresponds to this tile type.
	 */
	private Image getImage(RenderableTile tile) {
		if (tile.getTileType() == TileType.PLAINS)
			return TILE_PLAINS;
		else if (tile.getTileType() == TileType.MOUNTAINS_1)
			return TILE_MOUNTAIN1;
		else if (tile.getTileType() == TileType.MOUNTAINS_2)
			return TILE_MOUNTAIN2;
		else if (tile.getTileType() == TileType.MOUNTAINS_3)
			return TILE_MOUNTAIN3;
		else if (tile.getTileType() == TileType.RIVER)
			return TILE_RIVER;
		else if (tile.getTileType() == TileType.TOWN)
			return TILE_TOWN;
		else
			return TILE_TOWN;
	}

	/**
	 * @param tile
	 *            A tile for which a production image is needed.
	 * @return The image that corresponds to this tile's production type.
	 */
	private Image getProductionImage(RenderableTile tile) {
		if (tile.getProductionType() == ProductionType.CRYSTITE)
			return TILE_PROD_CRYSTITE;
		else if (tile.getProductionType() == ProductionType.ENERGY)
			return TILE_PROD_ENERGY;
		else if (tile.getProductionType() == ProductionType.SMITHORE)
			return TILE_PROD_ORE;
		else if (tile.getProductionType() == ProductionType.FOOD)
			return TILE_PROD_FOOD;
		else
			return null;
	}
}
